﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
using System.Security.Permissions;

namespace WinBot
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            if (File.Exists("settings.conf"))
            {
                Configurator conf = new Configurator("settings.conf");
                try
                {
                    Settings.Version = conf.GetProperty("Version");
                    Settings.MouseMoveTimeout = Convert.ToDouble(conf.GetProperty("MouseMoveTimeout").Replace(".", ","));
                    Settings.MousePressTimeout = Convert.ToDouble(conf.GetProperty("MousePressTimeout").Replace(".", ","));
                    Settings.MouseReleaseTimeout = Convert.ToDouble(conf.GetProperty("MouseReleaseTimeout").Replace(".", ","));
                    Settings.KeyboardPressTimeout = Convert.ToDouble(conf.GetProperty("KeyboardPressTimeout").Replace(".", ","));
                    Settings.KeyboardReleaseTimeout = Convert.ToDouble(conf.GetProperty("KeyboardReleaseTimeout").Replace(".", ","));
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            MouseHook.MouseActionPressed += new MouseEventHandler(MouseHook_MouseActionPressed);
            MouseHook.MouseActionReleased += new MouseEventHandler(MouseHook_MouseActionReleased);
            MouseHook.MouseActionMoved += new MouseEventHandler(MouseHook_MouseActionMoved);
            KeyboardHook.KeyboardActionPressed += new KeyEventHandler(KeyboardHook_KeyboardActionPressed);
            KeyboardHook.KeyboardActionReleased += new KeyEventHandler(KeyboardHook_KeyboardActionReleased);
            KeyboardHook.Start();
            NativeMethods.RegisterHotKey(this.Handle, hk_Record, (int)KeyModifiers.Control, (int)Keys.NumPad1);
            NativeMethods.RegisterHotKey(this.Handle, hk_Stop, (int)KeyModifiers.Control, (int)Keys.NumPad2);
            NativeMethods.RegisterHotKey(this.Handle, hk_Play, (int)KeyModifiers.Control, (int)Keys.NumPad3);
            AddForm.FormClose += new EventHandler(AddForm_Closing);
            UpdateStatusStrip();
        }

        private List<WinEvent> events = new List<WinEvent>();
        private Thread ev_PlayThread;
        private bool ev_Stop = true;
        private double ev_delta = -1;
        private DateTime ev_lastTime;

        private const int hk_Record = 1;
        private const int hk_Stop = 2;
        private const int hk_Play = 3;

        private void PlayThread()
        {
            int times = 1;
            if (checkBox1.Checked == true) times = Convert.ToInt32(numericUpDown1.Value);
            // Probably not infinite.
            if (times < 0) times = int.MaxValue;
            for (int n = 0; n < times; n++)
            {
                for (int i = 0; i < events.Count; i++)
                {
                    Thread.Sleep(Convert.ToInt32(events[i].Delta));
                    if (events[i].MouseArgs != null)
                    {
                        if (Cursor.Position != events[i].MouseArgs.Location)
                            Cursor.Position = events[i].MouseArgs.Location;
                        switch (events[i].MouseArgs.Button)
                        {
                            case System.Windows.Forms.MouseButtons.Left:
                                {
                                    if (events[i].ArgsEvent == WinEvent.ArgsEventType.Pressed)
                                        NativeMethods.mouse_event((uint)MouseEvent.LeftDown, 0, 0, 0, IntPtr.Zero);
                                    else
                                        if (events[i].ArgsEvent == WinEvent.ArgsEventType.Released)
                                            NativeMethods.mouse_event((uint)MouseEvent.LeftUp, 0, 0, 0, IntPtr.Zero);
                                    break;
                                }
                            case System.Windows.Forms.MouseButtons.Right:
                                {
                                    if (events[i].ArgsEvent == WinEvent.ArgsEventType.Pressed)
                                        NativeMethods.mouse_event((uint)MouseEvent.RightDown, 0, 0, 0, IntPtr.Zero);
                                    else
                                        if (events[i].ArgsEvent == WinEvent.ArgsEventType.Released)
                                            NativeMethods.mouse_event((uint)MouseEvent.RightUp, 0, 0, 0, IntPtr.Zero);
                                    break;
                                }
                        }
                    }
                    if (events[i].KeyboardArgs != null)
                    {
                        if (events[i].ArgsEvent == WinEvent.ArgsEventType.Pressed)
                            Emulate_KeyDown(events[i].KeyboardArgs.KeyCode);
                        else
                            if (events[i].ArgsEvent == WinEvent.ArgsEventType.Released)
                                Emulate_KeyUp(events[i].KeyboardArgs.KeyCode);
                    }
                }
            }
            this.Invoke((MethodInvoker)delegate { button3_Enable(); });
        }

        private void MouseHook_MouseActionPressed(object sender, MouseEventArgs e)
        {
            if (!ev_Stop)
            {
                if (ev_delta != -1)
                {
                    ev_delta = (DateTime.Now - ev_lastTime).TotalMilliseconds;
                    if (ev_delta < Settings.MousePressTimeout)
                        return;
                }
                else
                    ev_delta = 0;
                ev_lastTime = DateTime.Now;
                WinEvent we = new WinEvent(e, ev_delta, WinEvent.ArgsEventType.Pressed);
                events.Add(we);
                listBox1.Items.Add(we.ToString());
                UpdateStatusStrip();
            }
        }
        private void MouseHook_MouseActionReleased(object sender, MouseEventArgs e)
        {
            if (!ev_Stop)
            {
                if (ev_delta != -1)
                {
                    ev_delta = (DateTime.Now - ev_lastTime).TotalMilliseconds;
                    if (ev_delta < Settings.MouseReleaseTimeout)
                        return;
                }
                else
                    ev_delta = 0;
                ev_lastTime = DateTime.Now;
                WinEvent we = new WinEvent(e, ev_delta, WinEvent.ArgsEventType.Released);
                events.Add(we);
                listBox1.Items.Add(we.ToString());
                UpdateStatusStrip();
            }
        }
        private void MouseHook_MouseActionMoved(object sender, MouseEventArgs e)
        {
            if (!ev_Stop)
            {
                if (ev_delta != -1)
                {
                    ev_delta = (DateTime.Now - ev_lastTime).TotalMilliseconds;
                    if (ev_delta < Settings.MouseMoveTimeout)
                        return;
                }
                else
                    ev_delta = 0;

                ev_lastTime = DateTime.Now;
                WinEvent we = new WinEvent(e, ev_delta, WinEvent.ArgsEventType.None);
                events.Add(we);
                listBox1.Items.Add(we.ToString());
                UpdateStatusStrip();
            }
        }

        private void KeyboardHook_KeyboardActionPressed(object sender, KeyEventArgs e)
        {
            if (!ev_Stop)
            {
                if (ev_delta != -1)
                {
                    ev_delta = (DateTime.Now - ev_lastTime).TotalMilliseconds;
                    if (ev_delta < Settings.KeyboardPressTimeout)
                        return;
                }
                else
                    ev_delta = 0;
                ev_lastTime = DateTime.Now;
                WinEvent we = new WinEvent(e, ev_delta, WinEvent.ArgsEventType.Pressed);
                events.Add(we);
                listBox1.Items.Add(we.ToString());
                UpdateStatusStrip();
            }
        }
        private void KeyboardHook_KeyboardActionReleased(object sender, KeyEventArgs e)
        {
            if (!ev_Stop)
            {
                if (ev_delta != -1)
                {
                    ev_delta = (DateTime.Now - ev_lastTime).TotalMilliseconds;
                    if (ev_delta < Settings.KeyboardReleaseTimeout)
                        return;
                }
                else
                    ev_delta = 0;
                ev_lastTime = DateTime.Now;
                WinEvent we = new WinEvent(e, ev_delta, WinEvent.ArgsEventType.Released);
                events.Add(we);
                listBox1.Items.Add(we.ToString());
                UpdateStatusStrip();
            }
        }

        private void UpdateStatusStrip()
        {
            toolStripStatusLabel1.Text = "WinEvent.Count: " + events.Count + "; list.Count: " + listBox1.Items.Count;
        }

        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x0312)
            {
                switch ((int)m.WParam)
                {
                    case hk_Record:
                        {
                            button1_Click(null, new EventArgs());
                            break;
                        }
                    case hk_Stop:
                        {
                            button2_Click(null, new EventArgs());
                            break;
                        }
                    case hk_Play:
                        {
                            button3_Click(null, new EventArgs());
                            break;
                        }
                }
            }
            base.WndProc(ref m);
        }

        private void Emulate_KeyDown(System.Windows.Forms.Keys key)
        {
            NativeMethods.keybd_event((byte)key, 0x45, 0x0001 | 0, IntPtr.Zero);
        }
        private void Emulate_KeyUp(System.Windows.Forms.Keys key)
        {
            NativeMethods.keybd_event((byte)key, 0x45, 0x0001 | 0x0002, IntPtr.Zero);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            events.Clear();
            ev_Stop = false;
            ev_delta = -1;
            MouseHook.Start();
        }
        private void button2_Click(object sender, EventArgs e)
        {
            if (!ev_Stop)
            {
                ev_Stop = true;
            }
            if (ev_PlayThread != null)
                ev_PlayThread.Abort();
            button3.Enabled = true;
            MouseHook.Stop();
        }
        private void button3_Click(object sender, EventArgs e)
        {
            if (!ev_Stop) return;
            if (listBox1.Items.Count == 0) return;

            button3.Enabled = false;
            ev_PlayThread = new Thread(PlayThread);
            ev_PlayThread.Start();
        }
        private void button3_Enable()
        {
            button3.Enabled = true;
        }
        private void button4_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();
            events.Clear();
            UpdateStatusStrip();
        }
        private void button5_Click(object sender, EventArgs e)
        {
            int index = listBox1.SelectedIndex;
            if (index == -1)
                return;
            listBox1.SelectedIndex = -1;
            events.RemoveAt(index);
            listBox1.Items.RemoveAt(index);
            UpdateStatusStrip();
        }
        private void button6_Click(object sender, EventArgs e)
        {
            AddForm add = new AddForm();
            add.Show();
            add.Location = new Point(this.Location.X + 32, this.Location.Y + 64);
        }
        private void button7_Click(object sender, EventArgs e)
        {
            // up
            int index = listBox1.SelectedIndex;
            if (index != 0 && index != -1)
            {
                WinEvent selectedWE = events[listBox1.SelectedIndex];
                WinEvent exchangedWE = events[listBox1.SelectedIndex - 1];
                listBox1.Items[index] = exchangedWE.ToString();
                listBox1.Items[index - 1] = selectedWE.ToString();
                events[index] = exchangedWE;
                events[index - 1] = selectedWE;
                listBox1.SelectedIndex--;
            }
        }
        private void button8_Click(object sender, EventArgs e)
        {
            // down
            int index = listBox1.SelectedIndex;
            if (index != listBox1.Items.Count - 1 && index != -1)
            {
                WinEvent selectedWE = events[listBox1.SelectedIndex];
                WinEvent exchangedWE = events[listBox1.SelectedIndex + 1];
                listBox1.Items[index] = exchangedWE.ToString();
                listBox1.Items[index + 1] = selectedWE.ToString();
                events[index] = exchangedWE;
                events[index + 1] = selectedWE;
                listBox1.SelectedIndex++;
            }
        }
        private void button9_Click(object sender, EventArgs e)
        {
            // edit
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            KeyboardHook.Stop();
        }
        private void AddForm_Closing(object sender, EventArgs e)
        {
            WinEvent ev = AddForm.ev;
            events.Add(ev);
            if (AddForm.ev.MouseArgs != null)
            {
                if (ev.MouseArgs.Button == System.Windows.Forms.MouseButtons.None)
                    listBox1.Items.Add("MMove: " + ev.MouseArgs.Location.ToString() + "; ms: " + ev.Delta);
                switch (ev.ArgsEvent)
                {
                    case WinEvent.ArgsEventType.Pressed:
                        {
                            listBox1.Items.Add("MPClick: " + ev.MouseArgs.Button + "; pos: " + ev.MouseArgs.Location.ToString() + "; ms: " + ev.Delta);
                            break;
                        }
                    case WinEvent.ArgsEventType.Released:
                        {
                            listBox1.Items.Add("MRClick: " + ev.MouseArgs.Button + "; pos: " + ev.MouseArgs.Location.ToString() + "; ms: " + ev.Delta);
                            break;
                        }
                }
            }
            else
                if (AddForm.ev.KeyboardArgs != null)
                {
                    switch (ev.ArgsEvent)
                    {
                        case WinEvent.ArgsEventType.Pressed:
                            {
                                listBox1.Items.Add("KPKey: " + ev.KeyboardArgs.KeyCode + "; ms: " + ev.Delta);
                                break;
                            }
                        case WinEvent.ArgsEventType.Released:
                            {
                                listBox1.Items.Add("KRKey: " + ev.KeyboardArgs.KeyCode + "; ms: " + ev.Delta);
                                break;
                            }
                    }
                }
            UpdateStatusStrip();
        }
        private void listBox1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                int index = listBox1.SelectedIndex;
                if (index == -1)
                    return;
                listBox1.SelectedIndex = -1;
                events.RemoveAt(index);
                listBox1.Items.RemoveAt(index);
                UpdateStatusStrip();
            }
        }
        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            numericUpDown1.Enabled = checkBox1.Checked;
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!Directory.Exists("Scripts"))
                Directory.CreateDirectory("Scripts");

            if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                StringBuilder sb = new StringBuilder();
                foreach (WinEvent we in events)
                {
                    sb.Append((we.MouseArgs != null ? "Mouse = " + (we.MouseArgs.Button.ToString() != "None" ? we.MouseArgs.Button.ToString() : "Move") + "; Location = " + we.MouseArgs.Location.ToString() + "; " :
                        "Keyboard = " + we.KeyboardArgs.KeyCode.ToString() + "; ") + "Event = " + we.ArgsEvent + "; Delta = " + we.Delta + "\n");
                }
                File.WriteAllText(saveFileDialog1.FileName, sb.ToString());
            }
        }
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                events.Clear();
                listBox1.Items.Clear();
                string str = File.ReadAllText(openFileDialog1.FileName);
                string[] strev = str.Split('\n');
                for (int i = 0; i < strev.Length; i++)
                {
                    if (strev[i] != String.Empty)
                    {
                        string[] ev = strev[i].Split(';');
                        if (ev.Length != 3 && ev.Length != 4)
                            continue;
                        bool mouse = false;
                        string evtype = String.Empty;
                        Point evloc = new Point();
                        string evtype2 = String.Empty;
                        string evdelta = String.Empty;
                        try
                        {
                            if (Configurator.GetPropertyNameFromString(ev[0]) == "Mouse")
                            {
                                mouse = true;
                                evtype = Configurator.GetPropertyValueFromString(ev[0]);
                                string[] point = Configurator.GetPropertyValueFromString(ev[1]).Replace("{X=", "").Replace("Y=", "").Replace("}", "").Split(',');
                                evloc = new Point(int.Parse(point[0]), int.Parse(point[1]));
                                evtype2 = Configurator.GetPropertyValueFromString(ev[2]);
                                evdelta = Configurator.GetPropertyValueFromString(ev[3]);
                            }
                            else
                            {
                                if (Configurator.GetPropertyNameFromString(ev[0]) == "Keyboard")
                                {
                                    evtype = Configurator.GetPropertyValueFromString(ev[0]);
                                    evtype2 = Configurator.GetPropertyValueFromString(ev[1]);
                                    evdelta = Configurator.GetPropertyValueFromString(ev[2]);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            continue;
                        }
                        if (evtype != String.Empty && evtype2 != String.Empty && evdelta != String.Empty)
                        {
                            try
                            {
                                if (mouse)
                                {
                                    if (Configurator.GetPropertyValueFromString(ev[0]) != "Move")
                                    {
                                        WinEvent we = new WinEvent(
                                            new MouseEventArgs((MouseButtons)Enum.Parse(typeof(MouseButtons), Configurator.GetPropertyValueFromString(ev[0])),
                                                1, evloc.X, evloc.Y, 0),
                                            Convert.ToDouble(evdelta),
                                            (WinEvent.ArgsEventType)Enum.Parse(typeof(WinEvent.ArgsEventType), evtype2)
                                            );
                                        events.Add(we);
                                        listBox1.Items.Add(we.ToString());
                                    }
                                    else
                                    {
                                        WinEvent we = new WinEvent(
                                            new MouseEventArgs(System.Windows.Forms.MouseButtons.None, 0, evloc.X, evloc.Y, 0),
                                            Convert.ToDouble(evdelta),
                                            (WinEvent.ArgsEventType)Enum.Parse(typeof(WinEvent.ArgsEventType), evtype2)
                                            );
                                        events.Add(we);
                                        listBox1.Items.Add(we.ToString());
                                    }
                                }
                                else
                                {
                                    WinEvent we = new WinEvent(
                                            new KeyEventArgs((Keys)Enum.Parse(typeof(Keys), Configurator.GetPropertyValueFromString(ev[0]))),
                                            Convert.ToDouble(evdelta),
                                            (WinEvent.ArgsEventType)Enum.Parse(typeof(WinEvent.ArgsEventType), evtype2)
                                            );
                                    events.Add(we);
                                    listBox1.Items.Add(we.ToString());
                                }
                            }
                            catch (Exception ex)
                            {
                                continue;
                            }
                        }
                    }
                }
                UpdateStatusStrip();
            }
        }
        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Form_Options fo = new Form_Options();
            fo.Show();
            fo.Location = new Point(this.Location.X + 32, this.Location.Y + 64);
        }
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBox1 ab = new AboutBox1();
            ab.Show();
        }
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }

    public class WinEvent
    {
        private MouseEventArgs _margs;
        public MouseEventArgs MouseArgs
        {
            set { _margs = value; }
            get { return _margs; }
        }

        private KeyEventArgs _kargs;
        public KeyEventArgs KeyboardArgs
        {
            set { _kargs = value; }
            get { return _kargs; }
        }

        private double _delta;
        public double Delta
        {
            set { _delta = value; }
            get { return _delta; }
        }

        private ArgsEventType _argsEvent = ArgsEventType.None;
        public ArgsEventType ArgsEvent
        {
            set { _argsEvent = value; }
            get { return _argsEvent; }
        }

        public WinEvent(MouseEventArgs args, double delta, ArgsEventType argsType)
        {
            _margs = args;
            _delta = delta;
            _argsEvent = argsType;
        }
        public WinEvent(KeyEventArgs args, double delta, ArgsEventType argsType)
        {
            _kargs = args;
            _delta = delta;
            _argsEvent = argsType;
        }

        public enum ArgsEventType
        {
            None = 0,
            Pressed = 1,
            Released = 2
        }
        public override string ToString()
        {
            string str = String.Empty;
            if (_margs != null)
            {
                switch (_argsEvent)
                {
                    case ArgsEventType.None:
                        {
                            str = "MMove: " + _margs.Location.ToString() + "; ms: " + _delta;
                            break;
                        }
                    case ArgsEventType.Pressed:
                        {
                            str = "MPClick: " + _margs.Button + "; pos: " + _margs.Location.ToString() + "; ms: " + _delta;
                            break;
                        }
                    case ArgsEventType.Released:
                        {
                            str = "MRClick: " + _margs.Button + "; pos: " + _margs.Location.ToString() + "; ms: " + _delta;
                            break;
                        }
                }
            }
            else
                if (_kargs != null)
                {
                    switch (_argsEvent)
                    {
                        case ArgsEventType.Pressed:
                            {
                                str = "KPKey: " + _kargs.KeyCode + "; ms: " + _delta;
                                break;
                            }
                        case ArgsEventType.Released:
                            {
                                str = "KRKey: " + _kargs.KeyCode + "; ms: " + _delta;
                                break;
                            }
                    }
                }
            return str;
        }
    }

    public enum MouseEvent
    {
        Absolute = 0x8000,
        LeftDown = 0x0002,
        LeftUp = 0x0004,
        MiddleDown = 0x0020,
        MiddleUp = 0x0040,
        Move = 0x0001,
        RightDown = 0x0008,
        RightUp = 0x0010,
        WheelMove = 0x0800,
        XDown = 0x0080,
        XUp = 0x0100,
        Wheel = 0x0800,
        HWheel = 0x01000
    }
    public enum KeyModifiers
    {
        None = 0x0000,
        Alt = 0x0001,
        Control = 0x0002,
        NoRepeat = 0x4000,
        Shift = 0x0004,
        Windows = 0x0008
    }

    public static class MouseHook
    {
        public static event MouseEventHandler MouseActionPressed = delegate { };
        public static event MouseEventHandler MouseActionReleased = delegate { };
        public static event MouseEventHandler MouseActionMoved = delegate { };

        [HostProtectionAttribute(SecurityAction.LinkDemand, SharedState = true, Synchronization = true, ExternalProcessMgmt = true, SelfAffectingProcessMgmt = true)]
        [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Name = "FullTrust")]
        public static void Start()
        {
            _hookID = SetHook(_proc);


        }
        public static void Stop()
        {
            NativeMethods.UnhookWindowsHookEx(_hookID);
        }

        private static NativeMethods.LowLevelMouseProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;

        [HostProtectionAttribute(SecurityAction.LinkDemand, SharedState = true, Synchronization = true, ExternalProcessMgmt = true, SelfAffectingProcessMgmt = true)]
        [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Name = "FullTrust")]
        private static IntPtr SetHook(NativeMethods.LowLevelMouseProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return NativeMethods.SetWindowsHookEx(WH_MOUSE_LL, proc,
                  NativeMethods.GetModuleHandle(curModule.ModuleName), 0);
            }
        }
        private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
                switch ((MouseMessages)wParam)
                {
                    case MouseMessages.WM_LBUTTONDOWN:
                        {
                            MouseActionPressed(null, new MouseEventArgs(MouseButtons.Left, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
                            break;
                        }
                    case MouseMessages.WM_LBUTTONUP:
                        {
                            MouseActionReleased(null, new MouseEventArgs(MouseButtons.Left, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
                            break;
                        }
                    case MouseMessages.WM_MOUSEMOVE:
                        {
                            MouseActionMoved(null, new MouseEventArgs(MouseButtons.None, 0, Control.MousePosition.X, Control.MousePosition.Y, 0));
                            break;
                        }
                    case MouseMessages.WM_RBUTTONDOWN:
                        {
                            MouseActionPressed(null, new MouseEventArgs(MouseButtons.Right, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
                            break;
                        }
                    case MouseMessages.WM_RBUTTONUP:
                        {
                            MouseActionReleased(null, new MouseEventArgs(MouseButtons.Right, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
                            break;
                        }
                }
            }
            return NativeMethods.CallNextHookEx(_hookID, nCode, wParam, lParam);
        }

        private const int WH_MOUSE_LL = 14;

        private enum MouseMessages
        {
            WM_LBUTTONDOWN = 0x0201,
            WM_LBUTTONUP = 0x0202,
            WM_MOUSEMOVE = 0x0200,
            WM_MOUSEWHEEL = 0x020A,
            WM_RBUTTONDOWN = 0x0204,
            WM_RBUTTONUP = 0x0205
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct POINT
        {
            public int x;
            public int y;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct MSLLHOOKSTRUCT
        {
            public POINT pt;
            public uint mouseData;
            public uint flags;
            public uint time;
            public IntPtr dwExtraInfo;
        }
    }
    public static class KeyboardHook
    {
        public static event KeyEventHandler KeyboardActionPressed = delegate { };
        public static event KeyEventHandler KeyboardActionReleased = delegate { };

        private const int WH_KEYBOARD_LL = 13;

        private static NativeMethods.LowLevelKeyboardProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;

        [HostProtectionAttribute(SecurityAction.LinkDemand, SharedState = true, Synchronization = true, ExternalProcessMgmt = true, SelfAffectingProcessMgmt = true)]
        [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Name = "FullTrust")]
        public static void Start()
        {
            _hookID = SetHook(_proc);
        }
        public static void Stop()
        {
            NativeMethods.UnhookWindowsHookEx(_hookID);
        }

        [HostProtectionAttribute(SecurityAction.LinkDemand, SharedState = true, Synchronization = true, ExternalProcessMgmt = true, SelfAffectingProcessMgmt = true)]
        [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Name = "FullTrust")]
        private static IntPtr SetHook(NativeMethods.LowLevelKeyboardProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return NativeMethods.SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                    NativeMethods.GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        private static IntPtr HookCallback(
            int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0/* && wParam == (IntPtr)WM_KEYDOWN*/)
            {
                int vkCode = Marshal.ReadInt32(lParam);
                switch ((KeyboardMessages)wParam)
                {
                    case KeyboardMessages.WM_KEYDOWN:
                        {
                            if (vkCode == 162)
                                KeyboardActionPressed(null, new KeyEventArgs(Keys.ControlKey));
                            else
                                KeyboardActionPressed(null, new KeyEventArgs((Keys)vkCode));
                            break;
                        }
                    case KeyboardMessages.WM_KEYUP:
                        {
                            if (vkCode == 162)
                                KeyboardActionReleased(null, new KeyEventArgs(Keys.ControlKey));
                            else
                                KeyboardActionReleased(null, new KeyEventArgs((Keys)vkCode));
                            break;
                        }
                }
            }
            return NativeMethods.CallNextHookEx(_hookID, nCode, wParam, lParam);
        }

        private enum KeyboardMessages
        {
            WM_KEYDOWN = 0x0100,
            WM_KEYUP = 0x0101
        }
    }

    internal static class NativeMethods
    {
        [DllImport("user32.dll")]
        internal static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, IntPtr dwExtraInf);

        [DllImport("user32.dll")]
        internal static extern uint keybd_event(byte bVk, byte bScan, int dwFlags, IntPtr dwExtraInfo);

        [DllImport("user32.dll")]
        internal static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);

        internal delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern IntPtr SetWindowsHookEx(int idHook, LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        internal static extern IntPtr GetModuleHandle(string lpModuleName);

        internal delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
    }
}
